Fix a number of bugs with cargo clean
authorAlex Crichton <alex@alexcrichton.com>
Tue, 10 Nov 2015 17:41:06 +0000 (09:41 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Sun, 15 Nov 2015 21:02:39 +0000 (13:02 -0800)
* Clean out both host/target platforms if any are available.
* Clean out build script output.
* Add a --release flag to also be able to clean out release folder
* Be sure to clean out benchmarks, tests, etc.
* Cleaning out registry packages no longer panics

Closes #2121

src/bin/clean.rs
src/cargo/ops/cargo_clean.rs
tests/test_cargo_clean.rs

index 8aea04d35a70cc0eeb442549cc09c47a55bf9694..607f8f1236a78de5dbffc5a051b25c43d43c9cad 100644 (file)
@@ -12,6 +12,7 @@ struct Options {
     flag_verbose: bool,
     flag_quiet: bool,
     flag_color: Option<String>,
+    flag_release: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -25,6 +26,7 @@ Options:
     -p SPEC, --package SPEC ...  Package to clean artifacts for
     --manifest-path PATH         Path to the manifest to the package to clean
     --target TRIPLE              Target triple to clean output for (default all)
+    --release                    Whether or not to clean release artifacts
     -v, --verbose                Use verbose output
     -q, --quiet                  No output printed to stdout
     --color WHEN                 Coloring: auto, always, never
@@ -45,6 +47,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
         config: config,
         spec: &options.flag_package,
         target: options.flag_target.as_ref().map(|s| &s[..]),
+        release: options.flag_release,
     };
     ops::clean(&root, &opts).map(|_| None).map_err(|err| {
       CliError::from_boxed(err, 101)
index 7cf9fde0f2aba3ee844949a413e6129c810ac424..cf588ae2837f59a510c885ca3b3d6dbc3a21e6b6 100644 (file)
@@ -3,8 +3,9 @@ use std::fs;
 use std::io::prelude::*;
 use std::path::Path;
 
-use core::{Package, PackageSet, Profiles, Profile};
+use core::{Package, PackageSet, Profiles};
 use core::source::{Source, SourceMap};
+use core::registry::PackageRegistry;
 use util::{CargoResult, human, ChainError, Config};
 use ops::{self, Layout, Context, BuildConfig, Kind, Unit};
 
@@ -12,6 +13,7 @@ pub struct CleanOptions<'a> {
     pub spec: &'a [String],
     pub target: Option<&'a str>,
     pub config: &'a Config,
+    pub release: bool,
 }
 
 /// Cleans the project from build artifacts.
@@ -37,11 +39,19 @@ pub fn clean(manifest_path: &Path, opts: &CleanOptions) -> CargoResult<()> {
     // filenames and such
     let srcs = SourceMap::new();
     let pkgs = PackageSet::new(&[]);
-    let profiles = Profiles::default();
+
+    let dest = if opts.release {"release"} else {"debug"};
+    let host_layout = Layout::new(opts.config, &root, None, dest);
+    let target_layout = opts.target.map(|target| {
+        Layout::new(opts.config, &root, Some(target), dest)
+    });
+
     let cx = try!(Context::new(&resolve, &srcs, &pkgs, opts.config,
-                               Layout::at(target_dir),
-                               None, BuildConfig::default(),
-                               &profiles));
+                               host_layout, target_layout,
+                               BuildConfig::default(),
+                               root.manifest().profiles()));
+
+    let mut registry = PackageRegistry::new(opts.config);
 
     // resolve package specs and remove the corresponding packages
     for spec in opts.spec {
@@ -49,27 +59,31 @@ pub fn clean(manifest_path: &Path, opts: &CleanOptions) -> CargoResult<()> {
 
         // Translate the PackageId to a Package
         let pkg = {
-            let mut source = pkgid.source_id().load(opts.config);
-            try!(source.update());
-            (try!(source.get(&[pkgid.clone()]))).into_iter().next().unwrap()
+            try!(registry.add_sources(&[pkgid.source_id().clone()]));
+            (try!(registry.get(&[pkgid.clone()]))).into_iter().next().unwrap()
         };
 
         // And finally, clean everything out!
-        for target in pkg.targets().iter() {
-            // TODO: `cargo clean --release`
-            let layout = Layout::new(opts.config, &root, opts.target, "debug");
-            try!(rm_rf(&layout.fingerprint(&pkg)));
-            let profiles = [Profile::default_dev(), Profile::default_test()];
-            for profile in profiles.iter() {
-                let unit = Unit {
-                    pkg: &pkg,
-                    target: target,
-                    profile: profile,
-                    kind: Kind::Target,
-                };
-                for filename in try!(cx.target_filenames(&unit)).iter() {
-                    try!(rm_rf(&layout.dest().join(&filename)));
-                    try!(rm_rf(&layout.deps().join(&filename)));
+        for target in pkg.targets() {
+            for kind in [Kind::Host, Kind::Target].iter() {
+                let layout = cx.layout(&pkg, *kind);
+                try!(rm_rf(&layout.proxy().fingerprint(&pkg)));
+                try!(rm_rf(&layout.build(&pkg)));
+                let Profiles {
+                    ref release, ref dev, ref test, ref bench, ref doc,
+                    ref custom_build,
+                } = *root.manifest().profiles();
+                for profile in [release, dev, test, bench, doc, custom_build].iter() {
+                    let unit = Unit {
+                        pkg: &pkg,
+                        target: target,
+                        profile: profile,
+                        kind: *kind,
+                    };
+                    let root = cx.out_dir(&unit);
+                    for filename in try!(cx.target_filenames(&unit)).iter() {
+                        try!(rm_rf(&root.join(&filename)));
+                    }
                 }
             }
         }
index ff3313d9979842fb3ed9e41abc459264c46d026b..b816492e1d4157c37171980444afa6d3d733e9fa 100644 (file)
@@ -1,6 +1,8 @@
 use std::env;
 
-use support::{project, execs, main_file, basic_bin_manifest};
+use support::{git, project, execs, main_file, basic_bin_manifest};
+use support::{COMPILING, RUNNING};
+use support::registry::Package;
 use hamcrest::{assert_that, existing_dir, existing_file, is_not};
 
 fn setup() {
@@ -93,3 +95,135 @@ test!(clean_multiple_packages {
     assert_that(d1_path, is_not(existing_file()));
     assert_that(d2_path, is_not(existing_file()));
 });
+
+test!(clean_release {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [package]
+            name = "foo"
+            version = "0.0.1"
+            authors = []
+
+            [dependencies]
+            a = { path = "a" }
+        "#)
+        .file("src/main.rs", "fn main() {}")
+        .file("a/Cargo.toml", r#"
+            [package]
+            name = "a"
+            version = "0.0.1"
+            authors = []
+        "#)
+        .file("a/src/lib.rs", "");
+    p.build();
+
+    assert_that(p.cargo_process("build").arg("--release"),
+                execs().with_status(0));
+
+    assert_that(p.cargo("clean").arg("-p").arg("foo"),
+                execs().with_status(0));
+    assert_that(p.cargo("build").arg("--release"),
+                execs().with_status(0).with_stdout(""));
+
+    assert_that(p.cargo("clean").arg("-p").arg("foo").arg("--release"),
+                execs().with_status(0));
+    assert_that(p.cargo("build").arg("--release"),
+                execs().with_status(0).with_stdout(&format!("\
+{compiling} foo v0.0.1 ([..])
+", compiling = COMPILING)));
+});
+
+test!(build_script {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [package]
+            name = "foo"
+            version = "0.0.1"
+            authors = []
+            build = "build.rs"
+        "#)
+        .file("src/main.rs", "fn main() {}")
+        .file("build.rs", r#"
+            use std::path::PathBuf;
+            use std::env;
+
+            fn main() {
+                let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
+                if env::var("FIRST").is_ok() {
+                    std::fs::File::create(out.join("out")).unwrap();
+                } else {
+                    assert!(!std::fs::metadata(out.join("out")).is_ok());
+                }
+            }
+        "#)
+        .file("a/src/lib.rs", "");
+    p.build();
+
+    assert_that(p.cargo_process("build").env("FIRST", "1"),
+                execs().with_status(0));
+    assert_that(p.cargo("clean").arg("-p").arg("foo"),
+                execs().with_status(0));
+    assert_that(p.cargo("build").arg("-v"),
+                execs().with_status(0).with_stdout(&format!("\
+{compiling} foo v0.0.1 ([..])
+{running} `rustc build.rs [..]`
+{running} `[..]build-script-build[..]`
+{running} `rustc src[..]main.rs [..]`
+", compiling = COMPILING, running = RUNNING)));
+});
+
+test!(clean_git {
+    let git = git::new("dep", |project| {
+        project.file("Cargo.toml", r#"
+            [project]
+            name = "dep"
+            version = "0.5.0"
+            authors = []
+        "#)
+        .file("src/lib.rs", "")
+    }).unwrap();
+
+    let p = project("foo")
+        .file("Cargo.toml", &format!(r#"
+            [package]
+            name = "foo"
+            version = "0.0.1"
+            authors = []
+
+            [dependencies]
+            dep = {{ git = '{}' }}
+        "#, git.url()))
+        .file("src/main.rs", "fn main() {}");
+    p.build();
+
+    assert_that(p.cargo_process("build"),
+                execs().with_status(0));
+    assert_that(p.cargo("clean").arg("-p").arg("dep"),
+                execs().with_status(0).with_stdout(""));
+    assert_that(p.cargo("build"),
+                execs().with_status(0));
+});
+
+test!(registry {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [package]
+            name = "foo"
+            version = "0.0.1"
+            authors = []
+
+            [dependencies]
+            bar = "0.1"
+        "#)
+        .file("src/main.rs", "fn main() {}");
+    p.build();
+
+    Package::new("bar", "0.1.0").publish();
+
+    assert_that(p.cargo_process("build"),
+                execs().with_status(0));
+    assert_that(p.cargo("clean").arg("-p").arg("bar"),
+                execs().with_status(0).with_stdout(""));
+    assert_that(p.cargo("build"),
+                execs().with_status(0));
+});